Msg("Contraption Engine: Effects Library Present\n")

if (SERVER) then --Serverside Effect Dispatchers

function CDEffect_create_helper(entity, offset)
	local helper = ents.Create("helper_point")
	helper:SetPos(entity:LocalToWorld(offset))
	helper:Spawn()
	helper:SetParent(entity)
	return helper
end

function CDEffect_sprite_sustained(entity, offset, color, size, alpha, mode)
	local efxdata = EffectData()
	efxdata:SetEntity(entity)
	efxdata:SetOrigin(offset)
	efxdata:SetStart(Vector(color.r, color.g, color.b))
	efxdata:SetRadius(size)
	efxdata:SetMagnitude(alpha)
	efxdata:SetScale(mode)
	util.Effect( "sprite_sustained", efxdata)
end

function CDEffect_sprite_pulse(point, color, size, fadeduration, lifetime, entity)
	local efxdata = EffectData()
	if (entity != nil) then efxdata:SetEntity(entity) end
	efxdata:SetOrigin(point)
	efxdata:SetStart(Vector(color.r, color.g, color.b))
	efxdata:SetRadius(size)
	efxdata:SetMagnitude(fadeduration)
	efxdata:SetScale(lifetime)
	util.Effect( "sprite_flash", efxdata)
end

function CDEffect_impact_solid(point, color, size, lifetime, normal, entity)
	local efxdata = EffectData()
	if (entity != nil) then efxdata:SetEntity(entity) end
	efxdata:SetOrigin(point)
	efxdata:SetStart(Vector(color.r, color.g, color.b))
	efxdata:SetRadius(size)
	efxdata:SetMagnitude(lifetime)
	efxdata:SetNormal(normal)
	util.Effect( "impact_material", efxdata)
end

function CDEffect_impact_nonsolid(point, color, size, fadeduration, lifetime, normal, entity)
	local efxdata = EffectData()
	if (entity != nil) then efxdata:SetEntity(entity) end
	efxdata:SetOrigin(point)
	efxdata:SetStart(Vector(color.r, color.g, color.b))
	efxdata:SetRadius(size)
	efxdata:SetMagnitude(fadeduration)
	efxdata:SetScale(lifetime)
	efxdata:SetNormal(normal)
	util.Effect( "impact_energy", efxdata)
end

function CDEffect_impact_concussion(point, color, size, duration, entity)
	local efxdata = EffectData()
	if (entity != nil) then efxdata:SetEntity(entity) end
	efxdata:SetOrigin(point)
	efxdata:SetStart(Vector(color.r, color.g, color.b))
	efxdata:SetRadius(size)
	efxdata:SetMagnitude(duration)
	util.Effect( "impact_concussion", efxdata)
end

function CDEffect_beam_attached(entity, endpoint, color, width, duration, initalpha, mode)
	local efxdata = EffectData()
	efxdata:SetEntity(entity)
	efxdata:SetOrigin(endpoint)
	efxdata:SetStart(Vector(color.r, color.g, color.b))
	efxdata:SetRadius(width)
	local norstruct = Vector(duration, initalpha, 0)
	efxdata:SetNormal(norstruct)
	efxdata:SetScale(mode)
	util.Effect( "beam_pulse", efxdata)
end

function CDEffect_explosion_primitive(position)
	local efxdata = EffectData()
	efxdata:SetStart(position)
	efxdata:SetOrigin(position)
	efxdata:SetScale(1)
	util.Effect( "Explosion", efxdata)
end

function CDEffect_explosion_death_secondary(entity)
	if entity:IsValid() then
		local efxdata = EffectData()
		efxdata:SetEntity(entity)
		efxdata:SetMagnitude(100)
		util.Effect( "explosion_secondary", efxdata)
	end
end

function CDEffect_explosion_death_standard(origin, size)
	local efxdata = EffectData()
	efxdata:SetOrigin(origin)
	efxdata:SetMagnitude(size)
	util.Effect( "explosion_death", efxdata)
end

function CDEffect_explosion_death_epic(origin, size, wavesize)
	local efxdata = EffectData()
	efxdata:SetOrigin(origin)
	efxdata:SetMagnitude(size)
	efxdata:SetScale(wavesize)
	util.Effect( "explosion_death_epic", efxdata)
end

end

if (CLIENT) then --Clientside Effect Attachers

--CORE FUNCTIONS

function CDEffect_client_processall(entity)
	if entity.effectqueue != nil then
		for key,func in pairs(entity.effectqueue) do
			func(entity, key)
		end
	end
end

function CDEffect_client_prepentity(entity) --Initializes requisite storage tables
	entity.effectqueue = entity.effectqueue or {}
	entity.effectdata = entity.effectdata or {}
--[[ 	entity.Mat = entity.Mat or {}
	entity.SpriteMode = entity.SpriteMode or {}
	entity.Offset = entity.Offset or {}
	entity.Size = entity.Size or {}
	entity.Color = entity.Color or {} ]]
end

--FUNCTION HELPERS

function CDEffect_sprite_sustained_helper(entity, paramkey)
	if entity.effectdata[paramkey].NWRelevant and not entity:GetNetworkedBool("Drawmodel") then return end
	render.SetMaterial(entity.effectdata[paramkey].Mat)
	if entity.effectdata[paramkey].SpriteMode == 7 then render.UpdateRefractTexture() end
	render.DrawSprite(entity:LocalToWorld(entity.effectdata[paramkey].Offset), entity.effectdata[paramkey].Size, entity.effectdata[paramkey].Size, entity.effectdata[paramkey].Color)
end

function CDEffect_beam_trail_helper(entity, paramkey)
	if entity.effectdata[paramkey].NWRelevant and not entity:GetNetworkedBool("Drawmodel") then return end
	render.SetMaterial(entity.effectdata[paramkey].Mat)
	local numsegments = entity.effectdata[paramkey].Length
	for i=numsegments,2,-1 do
		entity.effectdata[paramkey].Segments[i] = entity.effectdata[paramkey].Segments[i - 1]
	end
	entity.effectdata[paramkey].Segments[1] = entity:GetPos()
	local totalsegments = #entity.effectdata[paramkey].Segments
	entity:SetRenderBoundsWS(entity.effectdata[paramkey].Segments[1], entity.effectdata[paramkey].Segments[totalsegments])
	local startwidth = ((entity.effectdata[paramkey].startwidth - entity.effectdata[paramkey].endwidth) * (totalsegments / numsegments)) + entity.effectdata[paramkey].endwidth
	local currentwidth = startwidth
	local widthincrement = (entity.effectdata[paramkey].startwidth - entity.effectdata[paramkey].endwidth) / totalsegments
	render.StartBeam(totalsegments)
	render.AddBeam(entity:GetPos(), startwidth, CurTime(), entity.effectdata[paramkey].Color)
	for i=1,totalsegments do
		if (i == 1 or i == totalsegments) and entity.effectdata[paramkey].Tapering then
			thiswidth = 0
		else
			thiswidth = currentwidth
		end
		render.AddBeam(entity.effectdata[paramkey].Segments[i], thiswidth, CurTime() + ( 1 / totalsegments ) * i, entity.effectdata[paramkey].Color)
		currentwidth = currentwidth - widthincrement
	end
	render.EndBeam()
end

--FUNCTION ASSIGNERS

function CDEffect_sprite_sustained(entity, offset, color, size, alpha, mode, NWRelevant)
	CDEffect_client_prepentity(entity)
	local paramkey = table.insert(entity.effectqueue, CDEffect_sprite_sustained_helper)
	entity.effectdata[paramkey] = {}
	
	local spritemode = mode
	local matstore
	
	if (spritemode == 1) then
		matstore = Material("Sprites/animglow02")
	elseif (spritemode == 2) then
		matstore = Material("Sprites/glow01")
	elseif (spritemode == 3) then
		matstore = Material("Sprites/glow1")
	elseif (spritemode == 4) then
		matstore = Material("Sprites/glow06")
	elseif (spritemode == 5) then
		matstore = Material("Sprites/lamphalo1")
	elseif (spritemode == 6) then
		matstore = Material("Sprites/light_glow01")
	elseif (spritemode == 7) then
		matstore = Material("effects/strider_pinch_dudv")
	elseif (spritemode == 8) then
		matstore = Material("Sprites/blueflare1")
	end
	
	if (spritemode != 7) then
		matstore:SetMaterialInt("$spriterendermode",5)
		--self.Mat:SetMaterialInt("$ignorez",1)
		matstore:SetMaterialInt("$illumfactor",8)
	end
	
	entity.effectdata[paramkey].Mat = matstore
	entity.effectdata[paramkey].SpriteMode = spritemode
	entity.effectdata[paramkey].Offset = offset
	entity.effectdata[paramkey].Size = size
	entity.effectdata[paramkey].Color = Color(color.r, color.g, color.b, alpha)
	entity.effectdata[paramkey].NWRelevant = NWRelevant
end

function CDEffect_beam_trail(entity, length, color, alpha, startwidth, endwidth, material, NWRelevant, taper)
	CDEffect_client_prepentity(entity)
	local paramkey = table.insert(entity.effectqueue, CDEffect_beam_trail_helper)
	entity.effectdata[paramkey] = {}
	
	entity.effectdata[paramkey].Mat = Material(material)
	entity.effectdata[paramkey].Length = length
	entity.effectdata[paramkey].Color = Color(color.r, color.g, color.b, alpha)
	entity.effectdata[paramkey].startwidth = startwidth
	entity.effectdata[paramkey].endwidth = endwidth
	entity.effectdata[paramkey].NWRelevant = NWRelevant
	entity.effectdata[paramkey].Segments = {}
	entity.effectdata[paramkey].Segments[1] = entity:GetPos()
	entity.effectdata[paramkey].Tapering = taper or false
end

end